#include <Imlib2.h>
#include <gtk/gtk.h>
#include <assert.h>

/*
 * Structures
 */
typedef struct _img_t
{
    Imlib_Image	    image;
    GtkWidget	    *win;
    unsigned int    loading:1,		    /* Wether the image is currently
					       loading */
		    fitImageOnWinResize;
    double	    zoom;
    GC		    gc;			    /* GC used for drawing / copying
					       pmap onto the image window. */
    Pixmap	    pmap;		    /* Pixmap containing the smooth
					       rendered image, for window
					       background. */
    int		    width, height,	    /* Dims of image */
		    orientation;	    /* EXIF orientation of the image */

    unsigned int    fullscreen:1,
		    wantRefresh:1;	    /* Wether window background needs to
					       be reset. */

    int		    winWidth, winHeight;    /* Dims of image window */
    GdkRectangle    clip,		    /* Part of the original image that
					       will be rendered. */
		    rend;		    /* Part of the window that will show
					       the image */

    Pixmap	    fullImg;		    /* Pixmap containing the full image
					       rendered at current zoom.
					       Generated on drag events for
					       better moving */
    unsigned int    moving:1;		    /* Wether the image currently being
					       moved with the mouse */
    gdouble	    clickx, clicky;	    /* Coordinates at which the move
					       started. */
} img_t;

enum _orientations
{
    TOP_LEFT = 0,
    TOP_RIGHT,
    BOT_LEFT
};

enum _zoom_modes
{
    FIT_TO_WINDOW = 0,
    FIT_TO_IMAGE
};

/*
 * vimview_t: Global info, X resources, config settings, etc.
 */
typedef struct _vimview_t
{
    Display	    *dpy;
    Visual	    *vis;
    Colormap	    cmap;
    int		    depth;

    unsigned int    msgMask;

    /* Config options */
    double	    defaultZoom;    /* Initial zoom factor */
    int		    maxWinSize;	    /* Max size (% of screen dims) to make the
				       window when fitting it to an image */
    gboolean	    fitImage;	    /* Fit image to window, ignoring user
				       specified zoom */
    unsigned	    defaultBG;	    /* Color of unused parts of image window */
    char	    *geomstring;    /* Initial geometry of image window. Only
				       used with --fit-image */
} vimview_t;

/*
 * Prototypes
 */
/* --------------------------------- main.c --------------------------------- */

void		message			( unsigned int	mask,
					  const char	*fmt, ... )
					__attribute__((
					    format( printf, 2, 3 )
					));
void		die			( const char *fmt, ... )
					__attribute__((
					    noreturn, format( printf, 1, 2 )
					));

/* -------------------------------- imgwin.c -------------------------------- */
void		imgInit			();
int		imgShow			( const char *file );

/* -------------------------------- options.c ------------------------------- */

void		initOptionValues	();
void		correctOptionValues	();

/* -------------------------------------------------------------------------- */

/*
 * Global variables
 */
extern img_t	    img;
extern vimview_t    v;
extern GOptionEntry options[];


/*
 * Macros
 */
#define APL_NAME "vimview"

#ifdef DEBUG
# define debug( level, fmt, ... )   \
    message( level, "%s:%d " fmt, __FILE__, __LINE__, ## __VA_ARGS__ )
#else
# define debug( fmt, ... )
#endif

#define infoMessage( fmt, ... ) \
    message( MSG_INFO, APL_NAME ": " fmt, ## __VA_ARGS__ )
#define warningMessage( fmt, ... ) \
    message( MSG_INFO, APL_NAME "\e[33m(warning)\e[m: " fmt, ## __VA_ARGS__ )
#define errorMessage( fmt, ... ) \
    message( MSG_INFO, APL_NAME "\e[31m(error)\e[m: " fmt, ## __VA_ARGS__ )

#define MSG_INFO	(0x0001)
#define MSG_WARN	(0x0002)
#define MSG_ERROR	(0x0004)
#define DBG_INFO	(0x0008)
#define DBG_WARN	(0x0010)
#define DBG_ERROR	(0x0020)
#define DBG_FUNCTRACE	(0x0040)
#define DBG_TMP		(0x4000)
#define DBG_DEBUG	(0x8000)

#define DEBUG_ALL	(0xff)

#define max( a, b )							\
({									\
    typeof(a)	_a = (a);						\
    typeof(b)	_b = (b);						\
									\
    _a > _b ? _a : _b;							\
})

#define min( a, b )							\
({									\
    typeof(a)	_a = (a);						\
    typeof(b)	_b = (b);						\
									\
    _a < _b ? _a : _b;							\
})

#define swap( a, b )							\
({									\
    typeof(a)	c = (a);						\
    a = (b);								\
    b = (c);								\
})
